package pers.ijfxu.testngext.listener;

import java.util.List;
import java.util.Map;

import org.assertj.core.util.Lists;
import org.testng.IInvokedMethod;
import org.testng.IReporter;
import org.testng.ISuite;
import org.testng.ITestResult;
import org.testng.xml.XmlSuite;

import cn.hutool.poi.excel.ExcelWriter;
import pers.ijfxu.testngext.context.RecArgFormat;
import pers.ijfxu.testngext.utils.CollectUtils;
import pers.ijfxu.testngext.utils.JsonUtils;
import pers.ijfxu.testngext.utils.TimeUtils;

/**
 * 测试报告生成器
 * 要求测试入参为RecArgFormat，否则会缺失部分字段如：
 * no、desc、expect result、priority
 * 测试用例自动补充test func、args、err msg、result
 * 测试执行完成将在test-class目录生成TestCase.年.月.日_小时.分钟.秒.xlsx
 * 
 * @author ijfxu
 * @since 2022/4/18 18:59
 */
public class TestCaseGeneratorListener implements IReporter {

    /** 成功用例集 */
    private List<RecArgFormat> SUCESSCASE = Lists.newArrayList();
    /** 失败用例集 */
    private List<RecArgFormat> FAILURECASE = Lists.newArrayList();
    /** 跳过用例集 */
    private List<RecArgFormat> SKIPCASE = Lists.newArrayList();

    private final Map<Integer, String> TESTSTATUS = CollectUtils.newHashMap(CollectUtils.newArrayList(1, 2, 3),
            CollectUtils.newArrayList("SUCCESS", "FAILURE", "SKIP"));

    @Override
    public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
        // 遍历所有测试套件进行测试用例收集
        for (ISuite suite : suites) {
            paraseIvokMethods(suite.getAllInvokedMethods());
        }
        // 收集所有测试用例
        List<RecArgFormat> casesList = CollectUtils.newArrayList();
        casesList.addAll(SUCESSCASE);
        casesList.addAll(FAILURECASE);
        casesList.addAll(SKIPCASE);
        // 将测试用例写入到excel文件中
        writeCaseToExcel(casesList);

    }

    /**
     * 遍历所有被调用的方法，从测试方法中获取测试用例
     * 
     * @param iInvokedMethods 测试过程中被调用的测试方法
     * @author ijfxu  
     * @since 2022/4/18 18:59
     */
    private void paraseIvokMethods(List<IInvokedMethod> iInvokedMethods) {

        for (IInvokedMethod iInvokedMethod : iInvokedMethods) {
            if (!iInvokedMethod.isTestMethod()) {
                continue;
            }
            ITestResult iTestResult = iInvokedMethod.getTestResult();
            getCaseList(iTestResult.getStatus()).add(paraseArgs(iTestResult));
        }
    }

    /**
     * 从testResult中获取测试用例
     * 
     * @param iTestResult 测试结果对象
     * @return 测试用例格式化对象
     * @author ijfxu  
     * @since 2022/4/18 18:59
     */
    private RecArgFormat paraseArgs(ITestResult iTestResult) {
        RecArgFormat testArgs = null;
        Object[] args = iTestResult.getParameters();
        if (null != args) {
            if (1 == args.length) {
                testArgs = JsonUtils.parseObj(args[0], RecArgFormat.class);
                if (null == testArgs || null == testArgs.args) {
                    testArgs = new RecArgFormat();
                    testArgs.setArgs(JsonUtils.toJsonStr(args[0]));
                }
            } else {
                testArgs = new RecArgFormat();
                Map<String, Object> multArgs = CollectUtils.newHashMap();
                for (int i = 0; i < args.length; i++) {
                    multArgs.put("arg[" + i + "]", args[i]);
                }
                testArgs.setArgs(JsonUtils.toJsonStr(multArgs));
            }

        }
        if (null == testArgs) {
            testArgs = new RecArgFormat();
        }
        int status = iTestResult.getStatus();
        testArgs.setResult(TESTSTATUS.get(status));
        testArgs.settFunc(String.format("%s.%s", iTestResult.getInstanceName(), iTestResult.getName()));
        if (iTestResult.getThrowable() != null) {
            testArgs.seterrMsg(iTestResult.getThrowable().getMessage());
        }
        return testArgs;
    }

    /**
     * 将测试用例集合写入到excel文档中
     * 
     * @param casesList 测试用例集合列表
     * @author ijfxu  
     * @since 2022/4/18 18:59
     */
    private void writeCaseToExcel(List<RecArgFormat> casesList) {
        String testCaseName = String.format("TestCase.%s.xlsx", TimeUtils.now());
        ExcelWriter excelWriter = new ExcelWriter(testCaseName);

        List<String> headLine = CollectUtils.newArrayList("no", "desc", "test func", "args", "expect result",
                "err msg", "result", "priority");
        for (int i = 0; i < headLine.size(); i++) {
            excelWriter.writeCellValue(i, 0, headLine.get(i));
        }

        for (int i = 1; i < casesList.size() + 1; i++) {
            RecArgFormat cell = casesList.get(i - 1);
            List<String> datas = CollectUtils.newArrayList(String.valueOf(cell.no), cell.desc, cell.tFunc, cell.args,
                    cell.exp, cell.errMsg, cell.result, String.valueOf(cell.priority));
            for (int j = 0; j < datas.size(); j++) {
                excelWriter.writeCellValue(j, i, datas.get(j));
            }

        }
        excelWriter.flush();
        excelWriter.close();
    }

    /**
     * 通过测试状态获取测试用例列表
     * 
     * @param value 测试状态值
     * @return 测试用例列表
     * @author ijfxu  
     * @since 2022/4/18 18:59
     */
    private List<RecArgFormat> getCaseList(int value) {
        switch (value) {
            case 1:
                return this.SUCESSCASE;
            case 2:
                return this.FAILURECASE;
            case 3:
                return this.SKIPCASE;
            default:
                return null;

        }
    }
}
